package com.diy.sigmund.diycommon.spring.advice;

import com.diy.sigmund.diycommon.spring.anno.SecurityParameter;
import com.diy.sigmund.diycommon.spring.config.CustomCommonConfig;
import com.diy.sigmund.diycommon.util.encrypt.AesEncryptUtil;
import com.diy.sigmund.diycommon.util.json.JacksonUtil;
import java.lang.reflect.Method;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 返回数据加密
 *
 * @author ylm-sigmund
 * @since 2021/8/17 15:31
 */
@ControllerAdvice
@Order(9)
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    private CustomCommonConfig customCommonConfig;
    private final static Logger log = LoggerFactory.getLogger(MyResponseBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        // log.info("MyResponseBodyAdvice supports");
        final boolean encryptEnabled = customCommonConfig.isEncryptEnabled();
        // 加解密配置为false时，不走加解密
        if (!encryptEnabled) {
            return false;
        }
        final Method method = methodParameter.getMethod();
        // 判断方法不为空
        if (Objects.isNull(method)) {
            return false;
        }
        // 判断方法上是否有该注解
        if (!method.isAnnotationPresent(SecurityParameter.class)) {
            return false;
        }
        final SecurityParameter securityParameter = methodParameter.getMethodAnnotation(SecurityParameter.class);
        return securityParameter.outEncode();
    }

    /**
     * <br>在选择HttpMessageConverter之后和调用它的 write 方法之前调用。
     * <br>参数：
     * <br>body – 要写入的正文
     * <br>returnType - 控制器方法的返回类型
     * <br>selectedContentType – 通过内容协商选择的内容类型
     * <br>selectedConverterType – 选择写入响应的转换器类型
     * <br>request – 当前请求
     * <br>response – 当前响应
     * <br>回报：
     * <br>传入的主体或修改的（可能是新的）实例
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass,
            ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        log.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
        try {
            String result = JacksonUtil.toJson(body);
            final String encrypt = AesEncryptUtil.encrypt(result);
            log.info("加密后的数据是{}", encrypt);
            return encrypt;
        } catch (Exception e) {
            log.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常：" + e);
            return body;
        }
    }
}
